package com.huahai.manager.upload;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import com.huahai.cofig.CosClientConfig;
import com.huahai.exception.BusinessException;
import com.huahai.exception.ErrorCode;
import com.huahai.manager.CosManager;
import com.huahai.pojo.dto.file.UploadPictureDTO;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.ciModel.persistence.CIObject;
import com.qcloud.cos.model.ciModel.persistence.ImageInfo;
import com.qcloud.cos.model.ciModel.persistence.ProcessResults;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * 贴合业务代码的图片上传通用类
 * @author huahai
 */
@Slf4j
public abstract class PictureUploadTemplate {

    @Resource
    private CosManager cosManager;

    @Resource
    CosClientConfig cosClientConfig;

    /**
     * 校验图片
     * @param inputResource 数据输入源
     */
    public abstract void validPicture(Object inputResource);

    /**
     * 获取原始文件名
     * @param inputResource 数据输入源
     * @return 原始文件名
     */
    public abstract String getOriginalFilename(Object inputResource);


    /**
     * 处理数据的来源
     * @param inputResource 数据输入源
     * @param file 临时文件
     */
    public abstract void processFile(Object inputResource, File file) throws IOException;


    /**
     * 上传图片
     *
     * @param inputResource    数据输入源
     * @param uploadPathPrefix 上传路径前缀 (不同用户可以指定不同的前缀)
     * @return 图片信息
     */
    public UploadPictureDTO uploadPicture(Object inputResource, String uploadPathPrefix) {
        // 1. 校验图片
        validPicture(inputResource);
        // 2. 图片上传地址
        String uuid = RandomUtil.randomString(8);
        String originFilename = getOriginalFilename(inputResource);
        // 3. 拼接上传文件的文件名
        String uploadFilename = String.format("%s_%s.%s", DateUtil.formatDate(new Date()), uuid, FileUtil.getSuffix(originFilename));
        // aLiYun AI 扩图上传图片时会自动拼接 ?... 导致上传失败
        // 这里截取 ? 之前的文件名
        if(uploadFilename.contains("?")){
            uploadFilename = uploadFilename.split("\\?")[0];
        }
        // 4. 拼接上传文件的路径
        String uploadPath = String.format("/%s/%s", uploadPathPrefix, uploadFilename);

        File file = null;
        try {
            // 5. 创建临时文件
            file = File.createTempFile(uploadPath, null);
            // 6. 处理数据来源 - 1. 本地 2. url
            processFile(inputResource , file);
            // 7. 上传图片
            PutObjectResult putObjectResult = cosManager.putPictureObject(uploadPath, file);
            // 拿到上传完的图片的信息（数据万象）
            ImageInfo imageInfo = putObjectResult.getCiUploadResult().getOriginalInfo().getImageInfo();

            // 新增：拿到压缩处理后的图片信息
            // 拿到处理后的图片信息
            ProcessResults processResults = putObjectResult.getCiUploadResult().getProcessResults();
            // 拿到处理后的图片结果列表
            List<CIObject> objectList = processResults.getObjectList();
            if(CollUtil.isNotEmpty(objectList)){
                // 拿到压缩后的图片信息
                CIObject compressedCiObject = objectList.get(0);
                // 默认缩略图等于压缩图
                CIObject thumbnailCiObject = compressedCiObject;
                if(objectList.size() > 1){
                    // 拿到缩略图的图片信息
                    thumbnailCiObject = objectList.get(1);
                }

                // 删除原图。方便管理
                cosManager.deleteOriginalImage(cosClientConfig.getBucket(), uploadPath);
                // 返回处理结果
                return buildUploadResult(originFilename, compressedCiObject, thumbnailCiObject, imageInfo);
            }

            // 8. 封装返回结果
            return buildUploadResult(imageInfo, originFilename, file, uploadPath);
        } catch (Exception e) {
            log.error("图片上传到对象存储失败", e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "上传失败");
        } finally {
            this.deleteTempFile(file);
        }
    }

    /**
     * 构建上传结果
     * @param originFilename 原始文件名
     * @param compressedCiObject 压缩处理后的图片信息
     * @return 上传结果
     */
    private UploadPictureDTO buildUploadResult(String originFilename, CIObject compressedCiObject, CIObject thumbnailCiObject, ImageInfo imageInfo) {
        UploadPictureDTO uploadPictureResult = new UploadPictureDTO();
        int picWidth = compressedCiObject.getWidth();
        int picHeight = compressedCiObject.getHeight();
        double picScale = NumberUtil.round(picWidth * 1.0 / picHeight, 2).doubleValue();
        uploadPictureResult.setPicName(FileUtil.mainName(originFilename));
        uploadPictureResult.setPicWidth(picWidth);
        uploadPictureResult.setPicHeight(picHeight);
        uploadPictureResult.setPicScale(picScale);
        uploadPictureResult.setPicFormat(compressedCiObject.getFormat());
        uploadPictureResult.setPicColor(imageInfo.getAve());
        uploadPictureResult.setPicSize(compressedCiObject.getSize().longValue());
        // 设置图片为压缩后的地址
        uploadPictureResult.setUrl(cosClientConfig.getHost() + "/" + compressedCiObject.getKey());
        // 设置缩略图的地址
        uploadPictureResult.setThumbnailUrl(cosClientConfig.getHost() + "/" + thumbnailCiObject.getKey());
        return uploadPictureResult;
    }


    /**
     * 构建上传结果
     * @param imageInfo 对象存储返回的图片信息
     * @param originFilename 原始文件名
     * @param file  文件
     * @param uploadPath 上传路径
     * @return 上传结果
     */
    private UploadPictureDTO buildUploadResult(ImageInfo imageInfo, String originFilename, File file, String uploadPath) {
        // 计算图片的宽高比
        int picWidth = imageInfo.getWidth();
        int picHeight = imageInfo.getHeight();
        double picScale = NumberUtil.round(picWidth * 1.0 / picHeight, 2).doubleValue();
        // 封装返回结果
        UploadPictureDTO uploadPictureDTO = new UploadPictureDTO();
        uploadPictureDTO.setPicName(FileUtil.mainName(originFilename));
        uploadPictureDTO.setPicWidth(picWidth);
        uploadPictureDTO.setPicHeight(picHeight);
        uploadPictureDTO.setPicScale(picScale);
        uploadPictureDTO.setPicFormat(imageInfo.getFormat());
        uploadPictureDTO.setPicSize(FileUtil.size(file));
        uploadPictureDTO.setPicColor(imageInfo.getAve());
        uploadPictureDTO.setUrl(cosClientConfig.getHost() + "/" + uploadPath);
        return uploadPictureDTO;
    }

    /**
     * 删除临时文件  
     */
    public void deleteTempFile(File file) {
        if (file == null) {
            return;
        }
        // 删除临时文件  
        boolean deleteResult = file.delete();
        if (!deleteResult) {
            log.error("file delete error, filepath = {}", file.getAbsolutePath());
        }
    }

}
